|
1
|
|
|
/*! |
|
2
|
|
|
* Stellar.js v0.6.5 |
|
3
|
|
|
* http://markdalgleish.com/projects/stellar.js |
|
4
|
|
|
* |
|
5
|
|
|
* Copyright 2018, Mark Dalgleish |
|
6
|
|
|
* This content is released under the MIT license |
|
7
|
|
|
* http://markdalgleish.mit-license.org |
|
8
|
|
|
*/ |
|
9
|
|
|
|
|
10
|
|
|
(function(factory) { |
|
11
|
|
|
if (typeof define === "function" && define.amd) { |
|
|
|
|
|
|
12
|
|
|
define(['jquery'], function($) { |
|
13
|
|
|
return factory($); |
|
14
|
|
|
}); |
|
15
|
|
|
} else if (typeof module === "object" && typeof module.exports === "object") { |
|
16
|
|
|
exports = factory(require('jquery')); |
|
17
|
|
|
} else { |
|
18
|
|
|
factory(jQuery); |
|
19
|
|
|
} |
|
20
|
|
|
})(function($) { |
|
21
|
|
|
|
|
22
|
|
|
var pluginName = 'stellar', |
|
23
|
|
|
defaults = { |
|
24
|
|
|
scrollProperty: 'scroll', |
|
25
|
|
|
positionProperty: 'position', |
|
26
|
|
|
horizontalScrolling: true, |
|
27
|
|
|
verticalScrolling: true, |
|
28
|
|
|
horizontalOffset: 0, |
|
29
|
|
|
verticalOffset: 0, |
|
30
|
|
|
responsive: false, |
|
31
|
|
|
parallaxBackgrounds: true, |
|
32
|
|
|
parallaxElements: true, |
|
33
|
|
|
hideDistantElements: true, |
|
34
|
|
|
hideElement: function($elem) { $elem.hide(); }, |
|
35
|
|
|
showElement: function($elem) { $elem.show(); } |
|
36
|
|
|
}, |
|
37
|
|
|
|
|
38
|
|
|
scrollProperty = { |
|
39
|
|
|
scroll: { |
|
40
|
|
|
getLeft: function($elem) { return $elem.scrollLeft(); }, |
|
41
|
|
|
setLeft: function($elem, val) { $elem.scrollLeft(val); }, |
|
42
|
|
|
|
|
43
|
|
|
getTop: function($elem) { return $elem.scrollTop(); }, |
|
44
|
|
|
setTop: function($elem, val) { $elem.scrollTop(val); } |
|
45
|
|
|
}, |
|
46
|
|
|
position: { |
|
47
|
|
|
getLeft: function($elem) { return parseInt($elem.css('left'), 10) * -1; }, |
|
48
|
|
|
getTop: function($elem) { return parseInt($elem.css('top'), 10) * -1; } |
|
49
|
|
|
}, |
|
50
|
|
|
margin: { |
|
51
|
|
|
getLeft: function($elem) { return parseInt($elem.css('margin-left'), 10) * -1; }, |
|
52
|
|
|
getTop: function($elem) { return parseInt($elem.css('margin-top'), 10) * -1; } |
|
53
|
|
|
}, |
|
54
|
|
|
transform: { |
|
55
|
|
|
getLeft: function($elem) { |
|
56
|
|
|
var computedTransform = getComputedStyle($elem[0])[prefixedTransform]; |
|
57
|
|
|
return (computedTransform !== 'none' ? parseInt(computedTransform.match(/(-?[0-9]+)/g)[4], 10) * -1 : 0); |
|
58
|
|
|
}, |
|
59
|
|
|
getTop: function($elem) { |
|
60
|
|
|
var computedTransform = getComputedStyle($elem[0])[prefixedTransform]; |
|
61
|
|
|
return (computedTransform !== 'none' ? parseInt(computedTransform.match(/(-?[0-9]+)/g)[5], 10) * -1 : 0); |
|
62
|
|
|
} |
|
63
|
|
|
} |
|
64
|
|
|
}, |
|
65
|
|
|
|
|
66
|
|
|
positionProperty = { |
|
67
|
|
|
position: { |
|
68
|
|
|
setLeft: function($elem, left) { $elem.css('left', left); }, |
|
69
|
|
|
setTop: function($elem, top) { $elem.css('top', top); } |
|
70
|
|
|
}, |
|
71
|
|
|
transform: { |
|
72
|
|
|
setPosition: function($elem, left, startingLeft, top, startingTop) { |
|
73
|
|
|
$elem[0].style[prefixedTransform] = 'translate3d(' + (left - startingLeft) + 'px, ' + (top - startingTop) + 'px, 0)'; |
|
74
|
|
|
} |
|
75
|
|
|
} |
|
76
|
|
|
}, |
|
77
|
|
|
|
|
78
|
|
|
// Returns a function which adds a vendor prefix to any CSS property name |
|
79
|
|
|
vendorPrefix = (function() { |
|
80
|
|
|
var prefixes = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/, |
|
81
|
|
|
style = $('script')[0].style, |
|
82
|
|
|
prefix = '', |
|
83
|
|
|
prop; |
|
84
|
|
|
|
|
85
|
|
|
for (prop in style) { |
|
86
|
|
|
if (prefixes.test(prop)) { |
|
87
|
|
|
prefix = prop.match(prefixes)[0]; |
|
88
|
|
|
break; |
|
89
|
|
|
} |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
if ('WebkitOpacity' in style) { prefix = 'Webkit'; } |
|
93
|
|
|
if ('KhtmlOpacity' in style) { prefix = 'Khtml'; } |
|
94
|
|
|
|
|
95
|
|
|
return function(property) { |
|
96
|
|
|
return prefix + (prefix.length > 0 ? property.charAt(0).toUpperCase() + property.slice(1) : property); |
|
97
|
|
|
}; |
|
98
|
|
|
}()), |
|
99
|
|
|
|
|
100
|
|
|
prefixedTransform = vendorPrefix('transform'), |
|
101
|
|
|
|
|
102
|
|
|
supportsBackgroundPositionXY = $('<div />', { style: 'background:#fff' }).css('background-position-x') !== undefined, |
|
103
|
|
|
|
|
104
|
|
|
setBackgroundPosition = (supportsBackgroundPositionXY ? |
|
105
|
|
|
function($elem, x, y) { |
|
106
|
|
|
$elem.css({ |
|
107
|
|
|
'background-position-x': x, |
|
108
|
|
|
'background-position-y': y |
|
109
|
|
|
}); |
|
110
|
|
|
} : |
|
111
|
|
|
function($elem, x, y) { |
|
112
|
|
|
$elem.css('background-position', x + ' ' + y); |
|
113
|
|
|
} |
|
114
|
|
|
), |
|
115
|
|
|
|
|
116
|
|
|
getBackgroundPosition = (supportsBackgroundPositionXY ? |
|
117
|
|
|
function($elem) { |
|
118
|
|
|
return [ |
|
119
|
|
|
$elem.css('background-position-x'), |
|
120
|
|
|
$elem.css('background-position-y') |
|
121
|
|
|
]; |
|
122
|
|
|
} : |
|
123
|
|
|
function($elem) { |
|
124
|
|
|
return $elem.css('background-position').split(' '); |
|
125
|
|
|
} |
|
126
|
|
|
), |
|
127
|
|
|
|
|
128
|
|
|
requestAnimFrame = ( |
|
129
|
|
|
window.requestAnimationFrame || |
|
130
|
|
|
window.webkitRequestAnimationFrame || |
|
131
|
|
|
window.mozRequestAnimationFrame || |
|
132
|
|
|
window.oRequestAnimationFrame || |
|
133
|
|
|
window.msRequestAnimationFrame || |
|
134
|
|
|
function(callback) { |
|
135
|
|
|
setTimeout(callback, 1000 / 60); |
|
136
|
|
|
} |
|
137
|
|
|
); |
|
138
|
|
|
|
|
139
|
|
|
function Plugin(element, options) { |
|
140
|
|
|
this.element = element; |
|
141
|
|
|
this.options = $.extend({}, defaults, options); |
|
142
|
|
|
|
|
143
|
|
|
this._defaults = defaults; |
|
144
|
|
|
this._name = pluginName; |
|
145
|
|
|
|
|
146
|
|
|
this.init(); |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
Plugin.prototype = { |
|
150
|
|
|
init: function() { |
|
151
|
|
|
this.options.name = pluginName + '_' + Math.floor(Math.random() * 1e9); |
|
152
|
|
|
|
|
153
|
|
|
this._defineElements(); |
|
154
|
|
|
this._defineGetters(); |
|
155
|
|
|
this._defineSetters(); |
|
156
|
|
|
this._handleWindowLoadAndResize(); |
|
157
|
|
|
this._detectViewport(); |
|
158
|
|
|
|
|
159
|
|
|
this.refresh({ firstLoad: true }); |
|
160
|
|
|
|
|
161
|
|
|
if (this.options.scrollProperty === 'scroll') { |
|
162
|
|
|
this._handleScrollEvent(); |
|
163
|
|
|
} else { |
|
164
|
|
|
this._startAnimationLoop(); |
|
165
|
|
|
} |
|
166
|
|
|
}, |
|
167
|
|
|
_defineElements: function() { |
|
168
|
|
|
if (this.element === document.body) this.element = window; |
|
|
|
|
|
|
169
|
|
|
this.$scrollElement = $(this.element); |
|
170
|
|
|
this.$element = (this.element === window ? $('body') : this.$scrollElement); |
|
171
|
|
|
this.$viewportElement = (this.options.viewportElement !== undefined ? $(this.options.viewportElement) : (this.$scrollElement[0] === window || this.options.scrollProperty === 'scroll' ? this.$scrollElement : this.$scrollElement.parent())); |
|
172
|
|
|
}, |
|
173
|
|
|
_defineGetters: function() { |
|
174
|
|
|
var self = this, |
|
175
|
|
|
scrollPropertyAdapter = scrollProperty[self.options.scrollProperty]; |
|
176
|
|
|
|
|
177
|
|
|
this._getScrollLeft = function() { |
|
178
|
|
|
return scrollPropertyAdapter.getLeft(self.$scrollElement); |
|
179
|
|
|
}; |
|
180
|
|
|
|
|
181
|
|
|
this._getScrollTop = function() { |
|
182
|
|
|
return scrollPropertyAdapter.getTop(self.$scrollElement); |
|
183
|
|
|
}; |
|
184
|
|
|
}, |
|
185
|
|
|
_defineSetters: function() { |
|
186
|
|
|
var self = this, |
|
187
|
|
|
scrollPropertyAdapter = scrollProperty[self.options.scrollProperty], |
|
188
|
|
|
positionPropertyAdapter = positionProperty[self.options.positionProperty], |
|
189
|
|
|
setScrollLeft = scrollPropertyAdapter.setLeft, |
|
190
|
|
|
setScrollTop = scrollPropertyAdapter.setTop; |
|
191
|
|
|
|
|
192
|
|
|
this._setScrollLeft = (typeof setScrollLeft === 'function' ? function(val) { |
|
193
|
|
|
setScrollLeft(self.$scrollElement, val); |
|
194
|
|
|
} : $.noop); |
|
195
|
|
|
|
|
196
|
|
|
this._setScrollTop = (typeof setScrollTop === 'function' ? function(val) { |
|
197
|
|
|
setScrollTop(self.$scrollElement, val); |
|
198
|
|
|
} : $.noop); |
|
199
|
|
|
|
|
200
|
|
|
this._setPosition = positionPropertyAdapter.setPosition || |
|
201
|
|
|
function($elem, left, startingLeft, top, startingTop) { |
|
202
|
|
|
if (self.options.horizontalScrolling) { |
|
203
|
|
|
positionPropertyAdapter.setLeft($elem, left, startingLeft); |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
if (self.options.verticalScrolling) { |
|
207
|
|
|
positionPropertyAdapter.setTop($elem, top, startingTop); |
|
208
|
|
|
} |
|
209
|
|
|
}; |
|
210
|
|
|
}, |
|
211
|
|
|
_handleWindowLoadAndResize: function() { |
|
212
|
|
|
var self = this, |
|
213
|
|
|
$window = $(window); |
|
214
|
|
|
|
|
215
|
|
|
if (self.options.responsive) { |
|
216
|
|
|
$window.bind('load.' + this.name, function() { |
|
217
|
|
|
self.refresh(); |
|
218
|
|
|
}); |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
$window.bind('resize.' + this.name, function() { |
|
222
|
|
|
self._detectViewport(); |
|
223
|
|
|
|
|
224
|
|
|
if (self.options.responsive) { |
|
225
|
|
|
self.refresh(); |
|
226
|
|
|
} |
|
227
|
|
|
}); |
|
228
|
|
|
}, |
|
229
|
|
|
refresh: function(options) { |
|
230
|
|
|
var self = this, |
|
231
|
|
|
oldLeft = self._getScrollLeft(), |
|
232
|
|
|
oldTop = self._getScrollTop(); |
|
233
|
|
|
|
|
234
|
|
|
if (!options || !options.firstLoad) { |
|
235
|
|
|
this._reset(); |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
this._setScrollLeft(0); |
|
239
|
|
|
this._setScrollTop(0); |
|
240
|
|
|
|
|
241
|
|
|
this._setOffsets(); |
|
242
|
|
|
this._findParticles(); |
|
243
|
|
|
this._findBackgrounds(); |
|
244
|
|
|
|
|
245
|
|
|
// Fix for WebKit background rendering bug |
|
246
|
|
|
if (options && options.firstLoad && /WebKit/.test(navigator.userAgent)) { |
|
|
|
|
|
|
247
|
|
|
$(window).on('load', function() { |
|
248
|
|
|
var oldLeft = self._getScrollLeft(), |
|
249
|
|
|
oldTop = self._getScrollTop(); |
|
250
|
|
|
|
|
251
|
|
|
self._setScrollLeft(oldLeft + 1); |
|
252
|
|
|
self._setScrollTop(oldTop + 1); |
|
253
|
|
|
|
|
254
|
|
|
self._setScrollLeft(oldLeft); |
|
255
|
|
|
self._setScrollTop(oldTop); |
|
256
|
|
|
}); |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
this._setScrollLeft(oldLeft); |
|
260
|
|
|
this._setScrollTop(oldTop); |
|
261
|
|
|
}, |
|
262
|
|
|
_detectViewport: function() { |
|
263
|
|
|
var viewportOffsets = this.$viewportElement[0] !== window ? this.$viewportElement.offset() : { top: 0, left: 0 }, |
|
264
|
|
|
hasOffsets = viewportOffsets !== null && viewportOffsets !== undefined; |
|
265
|
|
|
|
|
266
|
|
|
this.viewportWidth = this.$viewportElement.width(); |
|
267
|
|
|
this.viewportHeight = this.$viewportElement.height(); |
|
268
|
|
|
|
|
269
|
|
|
this.viewportOffsetTop = (hasOffsets ? viewportOffsets.top : 0); |
|
270
|
|
|
this.viewportOffsetLeft = (hasOffsets ? viewportOffsets.left : 0); |
|
271
|
|
|
}, |
|
272
|
|
|
_findParticles: function() { |
|
273
|
|
|
var self = this, |
|
274
|
|
|
scrollLeft = this._getScrollLeft(), |
|
|
|
|
|
|
275
|
|
|
scrollTop = this._getScrollTop(); |
|
|
|
|
|
|
276
|
|
|
|
|
277
|
|
|
if (this.particles !== undefined) { |
|
278
|
|
|
for (var i = this.particles.length - 1; i >= 0; i--) { |
|
279
|
|
|
this.particles[i].$element.data('stellar-elementIsActive', undefined); |
|
280
|
|
|
} |
|
281
|
|
|
} |
|
282
|
|
|
|
|
283
|
|
|
this.particles = []; |
|
284
|
|
|
|
|
285
|
|
|
if (!this.options.parallaxElements) return; |
|
|
|
|
|
|
286
|
|
|
|
|
287
|
|
|
this.$element.find('[data-stellar-ratio]').each(function(i) { |
|
|
|
|
|
|
288
|
|
|
var $this = $(this), |
|
289
|
|
|
horizontalOffset, |
|
290
|
|
|
verticalOffset, |
|
291
|
|
|
positionLeft, |
|
292
|
|
|
positionTop, |
|
293
|
|
|
marginLeft, |
|
294
|
|
|
marginTop, |
|
295
|
|
|
$offsetParent, |
|
296
|
|
|
offsetLeft, |
|
297
|
|
|
offsetTop, |
|
298
|
|
|
parentOffsetLeft = 0, |
|
299
|
|
|
parentOffsetTop = 0, |
|
300
|
|
|
tempParentOffsetLeft = 0, |
|
301
|
|
|
tempParentOffsetTop = 0; |
|
302
|
|
|
|
|
303
|
|
|
// Ensure this element isn't already part of another scrolling element |
|
304
|
|
|
if (!$this.data('stellar-elementIsActive')) { |
|
305
|
|
|
$this.data('stellar-elementIsActive', this); |
|
306
|
|
|
} else if ($this.data('stellar-elementIsActive') !== this) { |
|
307
|
|
|
return; |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
|
|
self.options.showElement($this); |
|
311
|
|
|
|
|
312
|
|
|
// Save/restore the original top and left CSS values in case we refresh the particles or destroy the instance |
|
313
|
|
|
if (!$this.data('stellar-startingLeft')) { |
|
314
|
|
|
$this.data('stellar-startingLeft', $this.css('left')); |
|
315
|
|
|
$this.data('stellar-startingTop', $this.css('top')); |
|
316
|
|
|
} else { |
|
317
|
|
|
$this.css('left', $this.data('stellar-startingLeft')); |
|
318
|
|
|
$this.css('top', $this.data('stellar-startingTop')); |
|
319
|
|
|
} |
|
320
|
|
|
|
|
321
|
|
|
positionLeft = $this.position().left; |
|
322
|
|
|
positionTop = $this.position().top; |
|
323
|
|
|
|
|
324
|
|
|
// Catch-all for margin top/left properties (these evaluate to 'auto' in IE7 and IE8) |
|
325
|
|
|
marginLeft = ($this.css('margin-left') === 'auto') ? 0 : parseInt($this.css('margin-left'), 10); |
|
326
|
|
|
marginTop = ($this.css('margin-top') === 'auto') ? 0 : parseInt($this.css('margin-top'), 10); |
|
327
|
|
|
|
|
328
|
|
|
offsetLeft = $this.offset().left - marginLeft; |
|
329
|
|
|
offsetTop = $this.offset().top - marginTop; |
|
330
|
|
|
|
|
331
|
|
|
// Calculate the offset parent |
|
332
|
|
|
$this.parents().each(function() { |
|
333
|
|
|
var $this = $(this); |
|
334
|
|
|
|
|
335
|
|
|
if ($this.data('stellar-offset-parent') === true) { |
|
336
|
|
|
parentOffsetLeft = tempParentOffsetLeft; |
|
337
|
|
|
parentOffsetTop = tempParentOffsetTop; |
|
338
|
|
|
$offsetParent = $this; |
|
339
|
|
|
|
|
340
|
|
|
return false; |
|
341
|
|
|
} else { |
|
|
|
|
|
|
342
|
|
|
tempParentOffsetLeft += $this.position().left; |
|
343
|
|
|
tempParentOffsetTop += $this.position().top; |
|
|
|
|
|
|
344
|
|
|
} |
|
345
|
|
|
}); |
|
346
|
|
|
|
|
347
|
|
|
// Detect the offsets |
|
348
|
|
|
horizontalOffset = ($this.data('stellar-horizontal-offset') !== undefined ? $this.data('stellar-horizontal-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-horizontal-offset') !== undefined ? $offsetParent.data('stellar-horizontal-offset') : self.horizontalOffset)); |
|
349
|
|
|
verticalOffset = ($this.data('stellar-vertical-offset') !== undefined ? $this.data('stellar-vertical-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-vertical-offset') !== undefined ? $offsetParent.data('stellar-vertical-offset') : self.verticalOffset)); |
|
350
|
|
|
|
|
351
|
|
|
// Add our object to the particles collection |
|
352
|
|
|
self.particles.push({ |
|
353
|
|
|
$element: $this, |
|
354
|
|
|
$offsetParent: $offsetParent, |
|
355
|
|
|
isFixed: $this.css('position') === 'fixed', |
|
356
|
|
|
horizontalOffset: horizontalOffset, |
|
357
|
|
|
verticalOffset: verticalOffset, |
|
358
|
|
|
startingPositionLeft: positionLeft, |
|
359
|
|
|
startingPositionTop: positionTop, |
|
360
|
|
|
startingOffsetLeft: offsetLeft, |
|
361
|
|
|
startingOffsetTop: offsetTop, |
|
362
|
|
|
parentOffsetLeft: parentOffsetLeft, |
|
363
|
|
|
parentOffsetTop: parentOffsetTop, |
|
364
|
|
|
stellarRatio: ($this.data('stellar-ratio') !== undefined ? $this.data('stellar-ratio') : 1), |
|
365
|
|
|
width: $this.outerWidth(true), |
|
366
|
|
|
height: $this.outerHeight(true), |
|
367
|
|
|
isHidden: false |
|
368
|
|
|
}); |
|
369
|
|
|
}); |
|
370
|
|
|
}, |
|
371
|
|
|
_findBackgrounds: function() { |
|
372
|
|
|
var self = this, |
|
373
|
|
|
scrollLeft = this._getScrollLeft(), |
|
374
|
|
|
scrollTop = this._getScrollTop(), |
|
375
|
|
|
$backgroundElements; |
|
376
|
|
|
|
|
377
|
|
|
this.backgrounds = []; |
|
378
|
|
|
|
|
379
|
|
|
if (!this.options.parallaxBackgrounds) return; |
|
|
|
|
|
|
380
|
|
|
|
|
381
|
|
|
$backgroundElements = this.$element.find('[data-stellar-background-ratio]'); |
|
382
|
|
|
|
|
383
|
|
|
if (this.$element.data('stellar-background-ratio')) { |
|
384
|
|
|
$backgroundElements = $backgroundElements.add(this.$element); |
|
385
|
|
|
} |
|
386
|
|
|
|
|
387
|
|
|
$backgroundElements.each(function() { |
|
388
|
|
|
var $this = $(this), |
|
389
|
|
|
backgroundPosition = getBackgroundPosition($this), |
|
390
|
|
|
horizontalOffset, |
|
391
|
|
|
verticalOffset, |
|
392
|
|
|
positionLeft, |
|
|
|
|
|
|
393
|
|
|
positionTop, |
|
|
|
|
|
|
394
|
|
|
marginLeft, |
|
395
|
|
|
marginTop, |
|
396
|
|
|
offsetLeft, |
|
397
|
|
|
offsetTop, |
|
398
|
|
|
$offsetParent, |
|
399
|
|
|
parentOffsetLeft = 0, |
|
400
|
|
|
parentOffsetTop = 0, |
|
401
|
|
|
tempParentOffsetLeft = 0, |
|
402
|
|
|
tempParentOffsetTop = 0; |
|
403
|
|
|
|
|
404
|
|
|
// Ensure this element isn't already part of another scrolling element |
|
405
|
|
|
if (!$this.data('stellar-backgroundIsActive')) { |
|
406
|
|
|
$this.data('stellar-backgroundIsActive', this); |
|
407
|
|
|
} else if ($this.data('stellar-backgroundIsActive') !== this) { |
|
408
|
|
|
return; |
|
409
|
|
|
} |
|
410
|
|
|
|
|
411
|
|
|
// Save/restore the original top and left CSS values in case we destroy the instance |
|
412
|
|
|
if (!$this.data('stellar-backgroundStartingLeft')) { |
|
413
|
|
|
$this.data('stellar-backgroundStartingLeft', backgroundPosition[0]); |
|
414
|
|
|
$this.data('stellar-backgroundStartingTop', backgroundPosition[1]); |
|
415
|
|
|
} else { |
|
416
|
|
|
setBackgroundPosition($this, $this.data('stellar-backgroundStartingLeft'), $this.data('stellar-backgroundStartingTop')); |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
// Catch-all for margin top/left properties (these evaluate to 'auto' in IE7 and IE8) |
|
420
|
|
|
marginLeft = ($this.css('margin-left') === 'auto') ? 0 : parseInt($this.css('margin-left'), 10); |
|
421
|
|
|
marginTop = ($this.css('margin-top') === 'auto') ? 0 : parseInt($this.css('margin-top'), 10); |
|
422
|
|
|
|
|
423
|
|
|
offsetLeft = $this.offset().left - marginLeft - scrollLeft; |
|
424
|
|
|
offsetTop = $this.offset().top - marginTop - scrollTop; |
|
425
|
|
|
|
|
426
|
|
|
// Calculate the offset parent |
|
427
|
|
|
$this.parents().each(function() { |
|
428
|
|
|
var $this = $(this); |
|
429
|
|
|
|
|
430
|
|
|
if ($this.data('stellar-offset-parent') === true) { |
|
431
|
|
|
parentOffsetLeft = tempParentOffsetLeft; |
|
432
|
|
|
parentOffsetTop = tempParentOffsetTop; |
|
433
|
|
|
$offsetParent = $this; |
|
434
|
|
|
|
|
435
|
|
|
return false; |
|
436
|
|
|
} else { |
|
|
|
|
|
|
437
|
|
|
tempParentOffsetLeft += $this.position().left; |
|
438
|
|
|
tempParentOffsetTop += $this.position().top; |
|
|
|
|
|
|
439
|
|
|
} |
|
440
|
|
|
}); |
|
441
|
|
|
|
|
442
|
|
|
// Detect the offsets |
|
443
|
|
|
horizontalOffset = ($this.data('stellar-horizontal-offset') !== undefined ? $this.data('stellar-horizontal-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-horizontal-offset') !== undefined ? $offsetParent.data('stellar-horizontal-offset') : self.horizontalOffset)); |
|
444
|
|
|
verticalOffset = ($this.data('stellar-vertical-offset') !== undefined ? $this.data('stellar-vertical-offset') : ($offsetParent !== undefined && $offsetParent.data('stellar-vertical-offset') !== undefined ? $offsetParent.data('stellar-vertical-offset') : self.verticalOffset)); |
|
445
|
|
|
|
|
446
|
|
|
self.backgrounds.push({ |
|
447
|
|
|
$element: $this, |
|
448
|
|
|
$offsetParent: $offsetParent, |
|
449
|
|
|
isFixed: $this.css('background-attachment') === 'fixed', |
|
450
|
|
|
horizontalOffset: horizontalOffset, |
|
451
|
|
|
verticalOffset: verticalOffset, |
|
452
|
|
|
startingValueLeft: backgroundPosition[0], |
|
453
|
|
|
startingValueTop: backgroundPosition[1], |
|
454
|
|
|
startingBackgroundPositionLeft: (isNaN(parseInt(backgroundPosition[0], 10)) ? 0 : parseInt(backgroundPosition[0], 10)), |
|
455
|
|
|
startingBackgroundPositionTop: (isNaN(parseInt(backgroundPosition[1], 10)) ? 0 : parseInt(backgroundPosition[1], 10)), |
|
456
|
|
|
startingPositionLeft: $this.position().left, |
|
457
|
|
|
startingPositionTop: $this.position().top, |
|
458
|
|
|
startingOffsetLeft: offsetLeft, |
|
459
|
|
|
startingOffsetTop: offsetTop, |
|
460
|
|
|
parentOffsetLeft: parentOffsetLeft, |
|
461
|
|
|
parentOffsetTop: parentOffsetTop, |
|
462
|
|
|
stellarRatio: ($this.data('stellar-background-ratio') === undefined ? 1 : $this.data('stellar-background-ratio')) |
|
463
|
|
|
}); |
|
464
|
|
|
}); |
|
465
|
|
|
}, |
|
466
|
|
|
_reset: function() { |
|
467
|
|
|
var particle, |
|
468
|
|
|
startingPositionLeft, |
|
469
|
|
|
startingPositionTop, |
|
470
|
|
|
background, |
|
471
|
|
|
i; |
|
472
|
|
|
|
|
473
|
|
|
for (i = this.particles.length - 1; i >= 0; i--) { |
|
474
|
|
|
particle = this.particles[i]; |
|
475
|
|
|
startingPositionLeft = particle.$element.data('stellar-startingLeft'); |
|
476
|
|
|
startingPositionTop = particle.$element.data('stellar-startingTop'); |
|
477
|
|
|
|
|
478
|
|
|
this._setPosition(particle.$element, startingPositionLeft, startingPositionLeft, startingPositionTop, startingPositionTop); |
|
479
|
|
|
|
|
480
|
|
|
this.options.showElement(particle.$element); |
|
481
|
|
|
|
|
482
|
|
|
particle.$element.data('stellar-startingLeft', null).data('stellar-elementIsActive', null).data('stellar-backgroundIsActive', null); |
|
483
|
|
|
} |
|
484
|
|
|
|
|
485
|
|
|
for (i = this.backgrounds.length - 1; i >= 0; i--) { |
|
486
|
|
|
background = this.backgrounds[i]; |
|
487
|
|
|
|
|
488
|
|
|
background.$element.data('stellar-backgroundStartingLeft', null).data('stellar-backgroundStartingTop', null); |
|
489
|
|
|
|
|
490
|
|
|
setBackgroundPosition(background.$element, background.startingValueLeft, background.startingValueTop); |
|
491
|
|
|
} |
|
492
|
|
|
}, |
|
493
|
|
|
destroy: function() { |
|
494
|
|
|
this._reset(); |
|
495
|
|
|
|
|
496
|
|
|
this.$scrollElement.unbind('resize.' + this.name).unbind('scroll.' + this.name); |
|
497
|
|
|
this._animationLoop = $.noop; |
|
498
|
|
|
|
|
499
|
|
|
$(window).unbind('load.' + this.name).unbind('resize.' + this.name); |
|
500
|
|
|
}, |
|
501
|
|
|
_setOffsets: function() { |
|
502
|
|
|
var self = this, |
|
503
|
|
|
$window = $(window); |
|
504
|
|
|
|
|
505
|
|
|
$window.unbind('resize.horizontal-' + this.name).unbind('resize.vertical-' + this.name); |
|
506
|
|
|
|
|
507
|
|
|
if (typeof this.options.horizontalOffset === 'function') { |
|
508
|
|
|
this.horizontalOffset = this.options.horizontalOffset(); |
|
509
|
|
|
$window.bind('resize.horizontal-' + this.name, function() { |
|
510
|
|
|
self.horizontalOffset = self.options.horizontalOffset(); |
|
511
|
|
|
}); |
|
512
|
|
|
} else { |
|
513
|
|
|
this.horizontalOffset = this.options.horizontalOffset; |
|
514
|
|
|
} |
|
515
|
|
|
|
|
516
|
|
|
if (typeof this.options.verticalOffset === 'function') { |
|
517
|
|
|
this.verticalOffset = this.options.verticalOffset(); |
|
518
|
|
|
$window.bind('resize.vertical-' + this.name, function() { |
|
519
|
|
|
self.verticalOffset = self.options.verticalOffset(); |
|
520
|
|
|
}); |
|
521
|
|
|
} else { |
|
522
|
|
|
this.verticalOffset = this.options.verticalOffset; |
|
523
|
|
|
} |
|
524
|
|
|
}, |
|
525
|
|
|
_repositionElements: function() { |
|
526
|
|
|
var scrollLeft = this._getScrollLeft(), |
|
527
|
|
|
scrollTop = this._getScrollTop(), |
|
528
|
|
|
horizontalOffset, |
|
529
|
|
|
verticalOffset, |
|
530
|
|
|
particle, |
|
531
|
|
|
fixedRatioOffset, |
|
532
|
|
|
background, |
|
533
|
|
|
bgLeft, |
|
534
|
|
|
bgTop, |
|
535
|
|
|
isVisibleVertical = true, |
|
536
|
|
|
isVisibleHorizontal = true, |
|
537
|
|
|
newPositionLeft, |
|
538
|
|
|
newPositionTop, |
|
539
|
|
|
newOffsetLeft, |
|
540
|
|
|
newOffsetTop, |
|
541
|
|
|
i; |
|
542
|
|
|
|
|
543
|
|
|
// First check that the scroll position or container size has changed |
|
544
|
|
|
if (this.currentScrollLeft === scrollLeft && this.currentScrollTop === scrollTop && this.currentWidth === this.viewportWidth && this.currentHeight === this.viewportHeight) { |
|
545
|
|
|
return; |
|
546
|
|
|
} else { |
|
|
|
|
|
|
547
|
|
|
this.currentScrollLeft = scrollLeft; |
|
548
|
|
|
this.currentScrollTop = scrollTop; |
|
549
|
|
|
this.currentWidth = this.viewportWidth; |
|
550
|
|
|
this.currentHeight = this.viewportHeight; |
|
551
|
|
|
} |
|
552
|
|
|
|
|
553
|
|
|
// Reposition elements |
|
554
|
|
|
for (i = this.particles.length - 1; i >= 0; i--) { |
|
555
|
|
|
particle = this.particles[i]; |
|
556
|
|
|
|
|
557
|
|
|
fixedRatioOffset = (particle.isFixed ? 1 : 0); |
|
558
|
|
|
|
|
559
|
|
|
// Calculate position, then calculate what the particle's new offset will be (for visibility check) |
|
560
|
|
|
if (this.options.horizontalScrolling) { |
|
561
|
|
|
newPositionLeft = (scrollLeft + particle.horizontalOffset + this.viewportOffsetLeft + particle.startingPositionLeft - particle.startingOffsetLeft + particle.parentOffsetLeft) * -(particle.stellarRatio + fixedRatioOffset - 1) + particle.startingPositionLeft; |
|
562
|
|
|
newOffsetLeft = newPositionLeft - particle.startingPositionLeft + particle.startingOffsetLeft; |
|
563
|
|
|
} else { |
|
564
|
|
|
newPositionLeft = particle.startingPositionLeft; |
|
565
|
|
|
newOffsetLeft = particle.startingOffsetLeft; |
|
566
|
|
|
} |
|
567
|
|
|
|
|
568
|
|
|
if (this.options.verticalScrolling) { |
|
569
|
|
|
newPositionTop = (scrollTop + particle.verticalOffset + this.viewportOffsetTop + particle.startingPositionTop - particle.startingOffsetTop + particle.parentOffsetTop) * -(particle.stellarRatio + fixedRatioOffset - 1) + particle.startingPositionTop; |
|
570
|
|
|
newOffsetTop = newPositionTop - particle.startingPositionTop + particle.startingOffsetTop; |
|
571
|
|
|
} else { |
|
572
|
|
|
newPositionTop = particle.startingPositionTop; |
|
573
|
|
|
newOffsetTop = particle.startingOffsetTop; |
|
574
|
|
|
} |
|
575
|
|
|
|
|
576
|
|
|
// Check visibility |
|
577
|
|
|
if (this.options.hideDistantElements) { |
|
578
|
|
|
isVisibleHorizontal = !this.options.horizontalScrolling || newOffsetLeft + particle.width > (particle.isFixed ? 0 : scrollLeft) && newOffsetLeft < (particle.isFixed ? 0 : scrollLeft) + this.viewportWidth + this.viewportOffsetLeft; |
|
579
|
|
|
isVisibleVertical = !this.options.verticalScrolling || newOffsetTop + particle.height > (particle.isFixed ? 0 : scrollTop) && newOffsetTop < (particle.isFixed ? 0 : scrollTop) + this.viewportHeight + this.viewportOffsetTop; |
|
580
|
|
|
} |
|
581
|
|
|
|
|
582
|
|
|
if (isVisibleHorizontal && isVisibleVertical) { |
|
583
|
|
|
if (particle.isHidden) { |
|
584
|
|
|
this.options.showElement(particle.$element); |
|
585
|
|
|
particle.isHidden = false; |
|
586
|
|
|
} |
|
587
|
|
|
|
|
588
|
|
|
this._setPosition(particle.$element, newPositionLeft, particle.startingPositionLeft, newPositionTop, particle.startingPositionTop); |
|
589
|
|
|
} else { |
|
590
|
|
|
if (!particle.isHidden) { |
|
591
|
|
|
this.options.hideElement(particle.$element); |
|
592
|
|
|
particle.isHidden = true; |
|
593
|
|
|
} |
|
594
|
|
|
} |
|
595
|
|
|
} |
|
596
|
|
|
|
|
597
|
|
|
// Reposition backgrounds |
|
598
|
|
|
for (i = this.backgrounds.length - 1; i >= 0; i--) { |
|
599
|
|
|
background = this.backgrounds[i]; |
|
600
|
|
|
|
|
601
|
|
|
fixedRatioOffset = (background.isFixed ? 0 : 1); |
|
602
|
|
|
bgLeft = (this.options.horizontalScrolling ? (scrollLeft + background.horizontalOffset - this.viewportOffsetLeft - background.startingOffsetLeft + background.parentOffsetLeft - background.startingBackgroundPositionLeft) * (fixedRatioOffset - background.stellarRatio) + 'px' : background.startingValueLeft); |
|
603
|
|
|
bgTop = (this.options.verticalScrolling ? (scrollTop + background.verticalOffset - this.viewportOffsetTop - background.startingOffsetTop + background.parentOffsetTop - background.startingBackgroundPositionTop) * (fixedRatioOffset - background.stellarRatio) + 'px' : background.startingValueTop); |
|
604
|
|
|
|
|
605
|
|
|
setBackgroundPosition(background.$element, bgLeft, bgTop); |
|
606
|
|
|
} |
|
607
|
|
|
}, |
|
608
|
|
|
_handleScrollEvent: function() { |
|
609
|
|
|
var self = this, |
|
610
|
|
|
ticking = false; |
|
611
|
|
|
|
|
612
|
|
|
var update = function() { |
|
613
|
|
|
self._repositionElements(); |
|
614
|
|
|
ticking = false; |
|
615
|
|
|
}; |
|
616
|
|
|
|
|
617
|
|
|
var requestTick = function() { |
|
618
|
|
|
if (!ticking) { |
|
619
|
|
|
requestAnimFrame(update); |
|
620
|
|
|
ticking = true; |
|
621
|
|
|
} |
|
622
|
|
|
}; |
|
623
|
|
|
|
|
624
|
|
|
this.$scrollElement.bind('scroll.' + this.name, requestTick); |
|
625
|
|
|
requestTick(); |
|
626
|
|
|
}, |
|
627
|
|
|
_startAnimationLoop: function() { |
|
628
|
|
|
var self = this; |
|
629
|
|
|
|
|
630
|
|
|
this._animationLoop = function() { |
|
631
|
|
|
requestAnimFrame(self._animationLoop); |
|
632
|
|
|
self._repositionElements(); |
|
633
|
|
|
}; |
|
634
|
|
|
this._animationLoop(); |
|
635
|
|
|
} |
|
636
|
|
|
}; |
|
637
|
|
|
|
|
638
|
|
|
$.fn[pluginName] = function(options) { |
|
639
|
|
|
var args = arguments; |
|
640
|
|
|
if (options === undefined || typeof options === 'object') { |
|
641
|
|
|
return this.each(function() { |
|
642
|
|
|
if (!$.data(this, 'plugin_' + pluginName)) { |
|
643
|
|
|
$.data(this, 'plugin_' + pluginName, new Plugin(this, options)); |
|
644
|
|
|
} |
|
645
|
|
|
}); |
|
646
|
|
|
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') { |
|
|
|
|
|
|
647
|
|
|
return this.each(function() { |
|
648
|
|
|
var instance = $.data(this, 'plugin_' + pluginName); |
|
649
|
|
|
if (instance instanceof Plugin && typeof instance[options] === 'function') { |
|
650
|
|
|
instance[options].apply(instance, Array.prototype.slice.call(args, 1)); |
|
651
|
|
|
} |
|
652
|
|
|
if (options === 'destroy') { |
|
653
|
|
|
$.data(this, 'plugin_' + pluginName, null); |
|
654
|
|
|
} |
|
655
|
|
|
}); |
|
656
|
|
|
} |
|
657
|
|
|
}; |
|
658
|
|
|
|
|
659
|
|
|
$[pluginName] = function(options) { |
|
|
|
|
|
|
660
|
|
|
var $window = $(window); |
|
661
|
|
|
return $window.stellar.apply($window, Array.prototype.slice.call(arguments, 0)); |
|
662
|
|
|
}; |
|
663
|
|
|
|
|
664
|
|
|
// Expose the scroll and position property function hashes so they can be extended |
|
665
|
|
|
$[pluginName].scrollProperty = scrollProperty; |
|
666
|
|
|
$[pluginName].positionProperty = positionProperty; |
|
667
|
|
|
|
|
668
|
|
|
// Expose the plugin class so it can be modified |
|
669
|
|
|
window.Stellar = Plugin; |
|
670
|
|
|
}); |
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.
To learn more about declaring variables in Javascript, see the MDN.